package loger

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
)

//////////////////////////////////////////////////////////////////////////////////
/////////////

type Level uint32

const (
	Fatal Level = iota
	Error
	Warns
	Infos
	Debug
)

var lstrs = [...]string{
	"CRIT",
	"EROR",
	"WARN",
	"INFO",
	"DEBG",
}

func (l Level) String() string {
	return lstrs[l]
}

var AllLevels = []Level{
	Fatal,
	Error,
	Warns,
	Infos,
	Debug,
}

//////////////////////////////////////////////////////////////////////////////////
/////////////

type Logger struct {
	lock      sync.Mutex
	writer    io.Writer
	hooks     Hooks
	level     Level
	formatter Formatter

	entrys sync.Pool
}

func New() *Logger {
	return &Logger{
		writer:    os.Stderr,
		hooks:     make(Hooks),
		level:     Infos,
		formatter: new(TextFormatter),
	}
}

func (logger *Logger) WithFields(fields map[string]interface{}) *Entry {
	//TODO: add entry pool
	//
	// entry, ok := logger.entrys.Get().(*Entry)
	// if !ok {
	// 	entry = &Entry{logger: logger}
	// }
	// defer logger.entrys.Put(entry)

	return NewEntry(logger).SetFields(fields)
}

func (logger *Logger) GetLevel() Level {
	return Level(atomic.LoadUint32((*uint32)(&logger.level)))
}

func (logger *Logger) SetLevel(level Level) {
	atomic.StoreUint32((*uint32)(&logger.level), uint32(level))
}

func (logger *Logger) SetOutput(writer io.Writer) {
	logger.lock.Lock()
	logger.writer = writer
	logger.lock.Unlock()
}

func (logger *Logger) SetFormatter(formatter Formatter) {
	logger.lock.Lock()
	logger.formatter = formatter
	logger.lock.Unlock()
}

func (logger *Logger) AddHook(hook Hook) {
	logger.lock.Lock()
	logger.hooks.Add(hook)
	logger.lock.Unlock()
}
